using System.Collections.Generic;

namespace Kopernikus.Parsing.GenericActions
{
    public class SemanticActionParametersFixupBuilder
    {
        private readonly Dictionary<int, int> m_parameterIndexFromRhsSymbolIndex = new Dictionary<int, int>();

        public ISemanticActionParametersFixup CreateFixup(Production production)
        {
            return new SemanticActionParametersFixup(CreateFixupArray(production));
        }

        public void MapParameterFromRhsSymbol(int parameterIndex, int rhsSymbolIndex)
        {
            if (m_parameterIndexFromRhsSymbolIndex.ContainsKey(parameterIndex))
            {
                throw new InvalidSemanticActionParameterException(
                    string.Format("Parameter {0} is mapped multiple times.", parameterIndex));
            }
            m_parameterIndexFromRhsSymbolIndex.Add(parameterIndex, rhsSymbolIndex);
        }

        private static bool IsValidIndex(int index, int length)
        {
            return (index >= 0) && (index < length);
        }

        private int[] CreateFixupArray(Production production)
        {
            if (m_parameterIndexFromRhsSymbolIndex.Count == 0)
            {
                return null;
            }

            int[] fixup = new int[m_parameterIndexFromRhsSymbolIndex.Count];
            foreach (KeyValuePair<int, int> pair in m_parameterIndexFromRhsSymbolIndex)
            {
                int parameterIndex = pair.Key;
                int rhsSymbolIndex = pair.Value;

                if (!IsValidIndex(parameterIndex, fixup.Length))
                {
                    throw new InvalidSemanticActionParameterException(
                        string.Format("Parameter {0} is out of bounds.", parameterIndex));
                }

                if (!IsValidIndex(rhsSymbolIndex, production.RHS.Length))
                {
                    throw new InvalidSemanticActionParameterException(
                        string.Format("Symbol {0} is mapped multiple times.", rhsSymbolIndex));
                }

                fixup[parameterIndex] = rhsSymbolIndex;
            }
            return fixup;
        }
    }
}